using System.Collections;
using System.Collections.Generic;
using Sirenix.OdinInspector;
using UnityEngine;

namespace GPUAnimationLib.Runtime
{
    /// <summary>
    /// GPU动画组件
    /// </summary>
    public class GPUAnimationComponent : SerializedMonoBehaviour
    {
        /// <summary>
        /// 总帧数
        /// </summary>
        [Title("总帧数")] public int TotalFrames;

        /// <summary>
        /// 动画数据
        /// </summary>
        [Title("动画数据")] public GPUAnimationData[] AnimationDatas;

        /// <summary>
        /// GPU附加物数据
        /// </summary>
        [Title("GPU附加物数据")] public GPUAttachmentData[] AttachmentDatas;

        /// <summary>
        /// 附加物计算数据
        /// </summary>
        [Title("附加物计算数据")] public AttachmentAnchorData AttachmentAnchorData;

        /// <summary>
        /// 动画名字与ID映射
        /// </summary>
        [Title("动画名字与ID映射"), ReadOnly] public Dictionary<string, int> AnimationNameToId;

        /// <summary>
        /// 主网格渲染器
        /// </summary>
        public MeshRenderer MainMeshRenderer { get; private set; }

        /// <summary>
        /// 主材质的材质属性
        /// </summary>
        public MaterialPropertyBlock MaterialPropertyBlock { get; private set; }

        int mAnimatorId;
        static readonly int ShaderPropID_Alpha = Shader.PropertyToID("_Alpha");

        bool mHasInit;

        void Awake()
        {
            Init();
        }

        public void Init()
        {
            if (mHasInit) return;
            mHasInit = true;
            MainMeshRenderer = transform.Find("MainMesh").GetComponent<MeshRenderer>();
            MaterialPropertyBlock = new MaterialPropertyBlock();
            MainMeshRenderer.GetPropertyBlock(MaterialPropertyBlock);
            MaterialPropertyBlock.SetFloat(ShaderPropID_Alpha, 1);
            MainMeshRenderer.SetPropertyBlock(MaterialPropertyBlock);
            mAnimatorId = GPUAnimationManager.Instance.RegisterAnimator(this);
            PlayAnimation(0, 1f, 0f, 0.25f);
            //FadeInOut(false);
        }

        [Button]
        void PlayAnim(string animationName)
        {
            PlayAnimation(animationName, 1f, 0f, 0.25f);
        }

        [Button]
        void PlayAnim(int animationId)
        {
            CompletedAction action = new CompletedAction()
            {
                Valid = true,
                Callback = () => { Debug.Log("动画播放完毕"); }
            };
            PlayAnimation(animationId, 1f, 0f, 0.25f, action);
        }

        Coroutine mFadeInOutCoroutine;

        public void FadeInOut(bool pBool)
        {
            StopFadeInOutCoroutine();
            float fadeInOutTime = 0.8f;
            if (pBool)
            {
                mFadeInOutCoroutine =
                    StartCoroutine(Fade(MainMeshRenderer, MaterialPropertyBlock, 1, 0, fadeInOutTime));
            }
            else
            {
                mFadeInOutCoroutine =
                    StartCoroutine(Fade(MainMeshRenderer, MaterialPropertyBlock, 0, 1, fadeInOutTime));
            }
        }

        void StopFadeInOutCoroutine()
        {
            if (mFadeInOutCoroutine != null)
            {
                StopCoroutine(mFadeInOutCoroutine);
                mFadeInOutCoroutine = null;
            }
        }

        IEnumerator Fade(MeshRenderer meshRenderer, MaterialPropertyBlock materialPropertyBlock, float fromAlpha,
            float toAlpha, float duration)
        {
            float t = 0;
            float alpha = 0;
            while (t < duration)
            {
                alpha = Mathf.Lerp(fromAlpha, toAlpha, t);
                materialPropertyBlock.SetFloat(ShaderPropID_Alpha, alpha);
                meshRenderer.SetPropertyBlock(materialPropertyBlock);
                yield return null;
                t += Time.deltaTime;
            }

            alpha = toAlpha;
            materialPropertyBlock.SetFloat(ShaderPropID_Alpha, alpha);
            meshRenderer.SetPropertyBlock(materialPropertyBlock);
        }

        void OnDestroy()
        {
            StopFadeInOutCoroutine();
            GPUAnimationManager.Instance.UnregisterAnimator(mAnimatorId);
        }

        void OnEnable()
        {
            if (mAnimatorId > 0)
                GPUAnimationManager.Instance.SetAnimatorActive(mAnimatorId, true);
        }

        void OnDisable()
        {
            if (mAnimatorId > 0)
                GPUAnimationManager.Instance.SetAnimatorActive(mAnimatorId, false);
        }

        public void PlayAnimation(string animationName, float speed, float startNormalizedTime, float transitionTime,
            CompletedAction completed = null)
        {
            PlayAnimation(GetAnimationId(animationName), speed, startNormalizedTime, transitionTime, completed);
        }

        public void PlayAnimation(int animationIndex, float speed, float startNormalizedTime, float transitionTime,
            CompletedAction completed = null)
        {
            if (animationIndex >= AnimationDatas.Length)
            {
                Debug.LogError($"PlayAnimation error! animationIndex : {animationIndex} not found!");
                return;
            }

            GPUAnimationManager.Instance.PlayAnimation(mAnimatorId, AnimationDatas[animationIndex], speed,
                startNormalizedTime, transitionTime, completed);
        }

        public void AddAttachment(Transform attachmentTrans, EAttachment attachment)
        {
            attachmentTrans.parent = transform;
            attachmentTrans.localPosition = Vector3.zero;
            attachmentTrans.localRotation = Quaternion.identity;
            attachmentTrans.localScale = Vector3.one;
            int attachmentIndex = GetAttachmentIndex(attachment);
            GPUAnimationManager.Instance.AddAttachment(mAnimatorId, attachmentTrans, attachmentIndex);
        }

        public void RemoveAttachment(EAttachment attachment)
        {
            int attachmentIndex = GetAttachmentIndex(attachment);
            GPUAnimationManager.Instance.RemoveAttachment(mAnimatorId, attachmentIndex);
        }

        int GetAttachmentIndex(EAttachment attachment)
        {
            int index = -1;
            for (int i = 0; i < AttachmentDatas.Length; i++)
            {
                if (AttachmentDatas[i].Attachment == attachment)
                {
                    index = i;
                    break;
                }
            }

            if (index < 0)
                Debug.LogError($"获取附加物索引出错, 添加未配置的附加物 : {attachment}");
            return index;
        }

        public int GetAnimationId(string animationName)
        {
            if (AnimationNameToId.TryGetValue(animationName, out var id))
            {
                return id;
            }
            else
            {
#if UNITY_EDITOR
                Debug.LogError(
                    $"GetAnimationId error! animationName : {animationName} not found! {transform.parent.gameObject.name}");
#endif
                return 0;
            }

            // #if UNITY_EDITOR
            // if (AnimationNameToId.TryGetValue(animationName, out var id))
            // {
            //     return id;
            // }
            // else
            // {
            //     Debug.LogError($"GetAnimationId error! animationName : {animationName} not found!");
            //     return 0;
            // }
            // #else
            //     return AnimationNameToId[animationName];
            // #endif
        }
    }
}